package com.bruce.demo.sequence.client;

import com.bruce.demo.sequence.config.GidServerConfig;
import com.bruce.demo.sequence.service.SequenceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.AbstractQueue;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * @author luotuan
 * @Description
 * @create 2020-05-15 22:00
 **/
@Service
public class SequenceClientServiceImpl implements SequenceClientService {
    @Autowired
    private GidServerConfig gidServerConfig;
    private ConcurrentHashMap<String, AbstractQueue<Long>> seqPool = new ConcurrentHashMap<>();
    @Autowired
    private SequenceService sequenceService;
    @Override
    public Long getSequence(String sysCode,String code){
        Long seq = null;
        String poolName = sysCode+"."+code;
        AbstractQueue<Long> queue = seqPool.get(poolName);
        for(int i =0;i<gidServerConfig.getTryTimes();i++){
            if(queue==null){
                queue = new ConcurrentLinkedQueue<>();
                SequenceHandler sequenceHandler = new SequenceHandler(sysCode,code,gidServerConfig.getClientCacheSize(),queue);
                Thread thread = new Thread(sequenceHandler);
                thread.start();
                seqPool.put(poolName,queue);
            }
            seq = queue.poll();
            if(seq!=null){
                System.out.println("sysCode【" + sysCode + "】,code【" + code + "】获取到的序列:【"+seq+"】");
                return seq;
            }else{
                try {
                    Thread.sleep(500L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        throw new RuntimeException("客户端获取gid异常");
    }

    class SequenceHandler implements Runnable{
        String sysCode;
        String code;
        int clientCacheSize;
        AbstractQueue<Long> queue;

        public SequenceHandler(String sysCode, String code, int clientCacheSize, AbstractQueue<Long> queue) {
            this.sysCode = sysCode;
            this.code = code;
            this.clientCacheSize = clientCacheSize;
            this.queue = queue;
        }

        @Override
        public void run() {
            while (true){
                if(queue.size()<(clientCacheSize*gidServerConfig.getRefillPercent())){
                    System.out.println("sysCode【" + sysCode + "】,code【" + code + "】客户端开始进行扩容");
                    ensureCapacity();
                }else{
                    try {
                        Thread.sleep(500L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        private void ensureCapacity() {
            Long gid = sequenceService.getSequence(sysCode,code);
            List<Long> capacityList = new ArrayList<>();
            for(int i=0;i< gidServerConfig.getClientIncrementSize();i++){
                Long result = gid++;
                capacityList.add(result);
            }
            queue.addAll(capacityList);
        }
    }
}
